#region CVS Log
/*
 * Version:
 *   $Id: COMMFrame.cs,v 1.11 2004/11/20 23:44:58 cwoodbury Exp $
 *
 * Revisions:
 *   $Log: COMMFrame.cs,v $
 *   Revision 1.11  2004/11/20 23:44:58  cwoodbury
 *   Removed unnecesary code.
 *
 *   Revision 1.10  2004/11/20 23:12:12  cwoodbury
 *   Removed TextEncodingType.ASCII type; replaced with ISO_8859_1 type
 *   or default type for EncodedString.
 *
 *   Revision 1.9  2004/11/19 18:38:47  cwoodbury
 *   Added code to catch and handle malformed data.
 *
 *   Revision 1.8  2004/11/16 07:08:14  cwoodbury
 *   Changed accessibility modifiers for some methods to internal or
 *   protected internal where appropriate.
 *
 *   Revision 1.7  2004/11/16 06:43:39  cwoodbury
 *   Fixed bug #1066848: EncodedStrings.CreateEncodedStrings() corrupted
 *   data in the optional leftover bytes.
 *
 *   Revision 1.6  2004/11/10 07:32:29  cwoodbury
 *   Factored out ParseFrameData() into ID3v2Frame.
 *
 *   Revision 1.5  2004/11/10 06:51:55  cwoodbury
 *   Hid CVS log messages away in #region
 *
 *   Revision 1.4  2004/11/10 04:44:16  cwoodbury
 *   Updated documentation.
 *
 *   Revision 1.3  2004/11/03 07:44:27  cwoodbury
 *   Added validity checks to parsing code.
 *
 *   Revision 1.2  2004/11/03 07:01:04  cwoodbury
 *   Updated known bug information.
 *
 *   Revision 1.1  2004/11/03 01:18:51  cwoodbury
 *   Added to ID3Sharp
 *
 */
#endregion

/* 
 * Author(s):
 *   Chris Woodbury 
 * 
 * Project Location:
 *	 http://id3sharp.sourceforge.net
 * 
 * License:
 *   Licensed under the Open Software License version 2.0
 */

using System;
using System.IO;
using System.Collections;

using ID3Sharp.IO;

namespace ID3Sharp.Frames
{
	/// <summary>
	/// A Comments frame.
	/// </summary>
	public class COMMFrame : TextInformationFrame
	{
		/// <summary>
		/// The default language code.
		/// </summary>
		private const string DEFAULT_LANGUAGE_CODE = "XXX";

		#region Fields
		/// <summary>
		/// The contents of the language code field.
		/// </summary>
		private string language;
		/// <summary>
		/// The contents of the description field.
		/// </summary>
		private EncodedString description;
		#endregion

		#region Constructors
		/// <summary>
		/// Creates a new COMMFrame.
		/// </summary>
		protected internal COMMFrame()
		{
			description = new EncodedString();
			language = DEFAULT_LANGUAGE_CODE;
		}
		#endregion

		#region Constructor/Initialize helpers
		/// <summary>
		/// Parses the raw frame data.
		/// </summary>
		/// <param name="frameData">The raw frame data.</param>
		/// <param name="version">The ID3v2 version of the tag being parsed.</param>
		protected override void ParseFrameData( byte[] frameData, ID3Versions version )
		{
			// Encoding type
			TextEncodingType encType = (TextEncodingType) frameData[0];

			// Language
			char[] languageBytes = new char[ 3 ];
			Array.Copy( frameData, 1, languageBytes, 0, languageBytes.Length );
			language = (new String( languageBytes )).ToUpper();
			
			// Text
			byte[] textBytes = new byte[ frameData.Length - 4 ];
			Array.Copy( frameData, 4, textBytes, 0, textBytes.Length );
			ArrayList strings  = EncodedString.CreateEncodedStrings( encType, textBytes );
			if ( strings.Count >= 2 && strings[0] is EncodedString && strings[1] is EncodedString )
			{
				description = (EncodedString) strings[0];
				text = (EncodedString) strings[1];
			}
		}
		#endregion

		#region Properties
		/// <summary>
		/// Gets and sets the contents of the frame's language field.
		/// </summary>
		public string Language
		{
			get
			{
				return language;
			}
			set
			{
				if ( value.Length == 3 )
				{
					if ( value.Equals( DEFAULT_LANGUAGE_CODE ) )
					{
						language = value;
					}
					else
					{
						language = value.ToLower();
					}
				}
				else
				{
					language = DEFAULT_LANGUAGE_CODE;
				}
			}
		}

		/// <summary>
		/// Gets and sets the contents of the frame's description field.
		/// </summary>
		public string Description
		{
			get
			{
				return description.String;
			}
			set
			{
				description.String = value;
			}
		}

		/// <summary>
		/// Gets the size (in bytes) of the frame (not including header).
		/// </summary>
		public override int Size
		{
			get
			{
				// encoding description byte + 3 language bytes + ...
				return 1 + 3 + description.Size + description.Termination.Length + text.Size;
			}
		}
		#endregion

		/// <summary>
		/// Returns a copy of this frame. Supports the prototype design pattern.
		/// </summary>
		/// <returns>A copy of this frame.</returns>
		public override ID3v2Frame Copy()
		{
			COMMFrame frameCopy = new COMMFrame();
			frameCopy.language = this.language;
			frameCopy.description = new EncodedString( this.description.TextEncodingType, this.description.String );

			return frameCopy;
		}

		/// <summary>
		/// Writes the frame to a stream.
		/// </summary>
		/// <param name="stream">The stream to write to.</param>
		/// <param name="version">The ID3v2 version to use in writing the frame.</param>
		public override void WriteToStream( Stream stream, ID3Versions version )
		{
			if ( (version & ID3Versions.V2) == ID3Versions.V2 )
			{
				EncodedString encodedLanguage = new EncodedString( TextEncodingType.ISO_8859_1, language );

				WriteHeaderToStream( stream, version );
				stream.WriteByte( (byte) text.TextEncodingType );
				stream.Write( encodedLanguage.Bytes, 0, 3 );
				stream.Write( description.Bytes, 0, description.Size );
				stream.Write( description.Termination, 0, description.Termination.Length );
				stream.Write( text.Bytes, 0, text.Size );
				stream.Flush();
			}
			else
			{
				throw new UnsupportedVersionException( version );
			}
		}
	}
}
